package haffman;

import java.io.*;

public class Decompress {


    private byte[] codeBuffer = new byte[256];
    private String[] huffmanCode = new String[256];
    private byte[] readBuffer = new byte[1024];
    private byte[] writeBuffer = new byte[1024];

    public String changeIntToString(int value) {
        String codeString = "";
        for (int i =0; i < 8; i++) {
            codeString = value % 2 + codeString;
            value = value / 2;
        }
        return codeString;
    }
    public String byte2bits(byte b) {
        int z = b;
        z |= 256;
        String str = Integer.toBinaryString(z);
        int len = str.length();
        return str.substring(len - 8, len);
    }

    public void decompress(String path, String destPath) throws IOException {
        FileInputStream fileInputStream = new FileInputStream(path);
        FileOutputStream fileOutputStream = new FileOutputStream(destPath);

        int codesLength = 0;
        StringBuffer huffmanCodes = new StringBuffer();
        fileInputStream.read(codeBuffer);
        for (int i = 0; i < 256; i++) {

            codesLength +=  codeBuffer[i];
        }
        int len = codesLength / 8;
        if ((codesLength & 7) != 0) {
            len++;
        }

        for (int i = 0; i < len; i++) {
            huffmanCodes.append(changeIntToString(fileInputStream.read()));
        }
        int start = 0;
        int end = 0;
        for (int i = 0; i < 256; i++) {
            if ( codeBuffer[i] != 0) {
                end += codeBuffer[i];
                huffmanCode[i] = huffmanCodes.substring(start,  end);
//              huffmanCodes.delete(0, codelength[i]);
                start = end;

            } else {
                huffmanCode[i] = "";
            }
        }
        huffmanCodes.setLength(0);
        StringBuffer codeContext = new StringBuffer();

        int fileLength = fileInputStream.read(readBuffer);
        int lastReadNum = 0;
        while (fileLength != -1) {
            if (fileLength < 1024) {
                fileLength--;
                lastReadNum = fileLength;
            }
            for (int i = 0; i < fileLength; i++) {
                codeContext.append(byte2bits(readBuffer[i]));
            }
            fileLength = fileInputStream.read(readBuffer);

        }


        codeContext.delete(codeContext.length() - readBuffer[lastReadNum], codeContext.length());
        int writeIndex = 0;
        for (int i = 0; i < codeContext.length(); i++){
            String subContext = codeContext.substring(0, i + 1);

            for (int j = 0; j < huffmanCode.length; j++){

                if (huffmanCode[j].equals(subContext)) {
                    writeBuffer[writeIndex] = (byte)j;
                    writeIndex++;
                    if (writeIndex == 1024) {
                        fileOutputStream.write(writeBuffer);
                        writeIndex = 0;
                        fileOutputStream.flush();
                    }
                    codeContext.delete(0, i + 1);
                    i = -1;
                    break;
                }
            }
        }
        if (writeIndex != 0) {
            fileOutputStream.write(writeBuffer,0,writeIndex);
        }
        fileOutputStream.close();
        fileInputStream.close();
    }



    public static void main(String[] args) throws IOException {
        Decompress decompress = new Decompress();
        decompress.decompress("E:\\youeryuanguanlixitong\\Test.zip","E:\\youeryuanguanlixitong\\t2.txt");

    }

}
